package cn.jx.cjm.common.base;

import cn.jx.cjm.common.aop.annotation.SortBy;
import cn.jx.cjm.common.aop.annotation.StatusSkip;
import cn.jx.cjm.common.contants.CommonCache;
import cn.jx.cjm.common.util.BeanUtils;
import cn.jx.cjm.common.enums.StatusEnum;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 请求dto继承基类
 *
 * @author WStars
 */
@Slf4j
public class BaseRequest<T> {

    public BaseRequest() {
        this.rules = CommonCache.departmentIds.get();
    }


    /**
     * 属性限定条件
     */
    @Setter
    @Getter
    List<BaseCondition> conditions;
    /**
     * 分页
     */
    @Setter
    private BasePage<T> page = new BasePage<>();

    public BasePage<T> getBasePage() {
        return page;
    }


    public void setClassName(String className) {
        try {
            Class<?> tClass = Class.forName(className);
            setColumnNames(tClass);
        } catch (ClassNotFoundException e) {
            log.error("类型：{} 查找失败：{}", className,e.getMessage());
            columnNames = new HashSet<>(0);
        }

    }
    /**
     * 需要转换的实体类中的字段集合(包括父类)
     */
    @Getter
    private Set<String> columnNames;

    private final static String UID = "serialVersionUID";
    private final static String STATUS = "status";
    private final static String RULE = "rule_sign";

    private final List<String> rules;


    private String sortBy = "createTime";

    private boolean hasStatus = false;
    private boolean skipStatus = false;
    private boolean desc = true;
    private boolean hasRule = false;


    /**
     * 查询条件
     */
    private final static String LIKE = "like";
    private final static String LIKE_LEFT = "%_";
    private final static String LIKE_RIGHT = "_%";
    private final static String NE = "<>";
    private final static String GT = ">";
    private final static String GE = ">=";
    private final static String LT = "<";
    private final static String LE = "<=";
    private final static String BT = "bt";
    private final static String IN = "in";

    public QueryWrapper<T> getQueryWrapper(Class<T> tClass) {
        setColumnNames(tClass);
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (desc) {
            queryWrapper.orderByDesc(BeanUtils.humpToUnderline(sortBy));
        } else {
            queryWrapper.orderByAsc(BeanUtils.humpToUnderline(sortBy));
        }
        if (hasStatus && !skipStatus) {
            queryWrapper.eq(BeanUtils.humpToUnderline(STATUS), StatusEnum.NORMAL.getCode());
        }
        if (hasRule) {
            queryWrapper.and(e -> {
                for (int i = 0; i< rules.size(); i++) {
                    if (!StringUtils.isEmpty(rules.get(i))) {
                        e.likeRight(RULE, rules.get(i));
                    } else {
                        e.eq("1" , 1);
                    }
                    if (i < rules.size() - 1) {
                        e.or();
                    }
                }
            });
        }
        return queryWrapper;
    }

    public QueryWrapper<T> getQueryWrapper() {
        //查询条件不为空则拼装条件
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        boolean statusQueryFlag = false;
        if (!CollectionUtils.isEmpty(conditions)) {
            //是否存在状态查询
            for (BaseCondition condition : conditions) {
                String column = condition.getColumn();
                Object value = condition.getValue();
                if (columnNames.contains(column) && null != value && !StringUtils.isEmpty(String.valueOf(value))) {
                    if (STATUS.equals(column)) {
                        statusQueryFlag = true;
                    }
                    column = BeanUtils.humpToUnderline(column);
                    switch (condition.getCondition()) {
                        case LIKE: queryWrapper.like(column, value); break;
                        case LIKE_LEFT: queryWrapper.likeLeft(column, value); break;
                        case LIKE_RIGHT: queryWrapper.likeRight(column, value); break;
                        case NE: queryWrapper.ne(column, value); break;
                        case GT: queryWrapper.gt(column, value); break;
                        case GE: queryWrapper.ge(column, value); break;
                        case LT: queryWrapper.lt(column, value); break;
                        case LE: queryWrapper.le(column, value); break;
                        case IN: queryWrapper.in(column, ((ArrayList<?>) value).toArray()); break;
                        case BT:
                            ArrayList<?> values = (ArrayList<?>) value;
                            if (!CollectionUtils.isEmpty(values) && values.size() == 2) {
                                queryWrapper.between(column, values.get(0), values.get(1));
                            }
                            break;
                        default: queryWrapper.eq(column, value); break;
                    }
                }
            }
        }
        if (!statusQueryFlag && hasStatus && !skipStatus) {
            queryWrapper.eq(BeanUtils.humpToUnderline(STATUS), StatusEnum.NORMAL.getCode());
        }
        if (hasRule) {
            for (String rule : rules) {
                queryWrapper.likeRight(RULE, rule);
            }
        }
        return queryWrapper;
    }


    /**
     * 创建分页条件
     */
    public Page<T> getPage() {
        Page<T> pageable = new Page<>(page.getCurrent(), page.getSize());

        List<OrderItem> orderItems = new ArrayList<>();
        //若存在升序排列字段
        if (!CollectionUtils.isEmpty(page.getAscs())) {
            for (String ascTemp : page.getAscs()) {
                if (columnNames.contains(ascTemp)) {
                    orderItems.add(OrderItem.asc(BeanUtils.humpToUnderline(ascTemp)));
                }
            }
        }
        //若存在降序排列字段
        if (!CollectionUtils.isEmpty(page.getDescs())) {
            for (String descTemp : page.getDescs()) {
                if (columnNames.contains(descTemp)) {
                    orderItems.add(OrderItem.desc(BeanUtils.humpToUnderline(descTemp)));
                }
            }
        }
        if (CollectionUtils.isEmpty(orderItems)) {
            orderItems.add(new OrderItem(BeanUtils.humpToUnderline(sortBy),!desc));
        }
        pageable.addOrder(orderItems);
        return pageable;
    }

    private void setColumnNames (Class<?> tClass) {
        // 跳过默认状态设为1
        StatusSkip statusSkip = tClass.getAnnotation(StatusSkip.class);
        if (null != statusSkip && statusSkip.skip()) {
            this.skipStatus = true;
        }
        Field[] tFields = tClass.getDeclaredFields();
        Field[] tSuperFields = tClass.getSuperclass().getDeclaredFields();
        columnNames = new HashSet<>(tFields.length + tSuperFields.length);
        for (Field field : tFields) {
            String fieldName = field.getName();
            if (!UID.equals(fieldName)) {
                // 去除表中不存在的字段
                if (null == field.getAnnotation(TableField.class) || field.getAnnotation(TableField.class).exist()) {
                    columnNames.add(fieldName);
                    if (STATUS.equalsIgnoreCase(fieldName)) {
                        hasStatus = true;
                    } else if (RULE.equalsIgnoreCase(fieldName)) {
                        hasRule = true;
                    } else if (null != field.getAnnotation(SortBy.class)) {
                        sortBy = fieldName;
                        desc = field.getAnnotation(SortBy.class).desc();
                    }
                }
            }
        }
        for (Field field : tSuperFields) {
            String fieldName = field.getName();
            if (!UID.equals(fieldName)) {
                columnNames.add(fieldName);
            }
        }
    }

    @Override
    public String toString() {
        return "{" +
                "conditions:" + JSON.toJSONString(conditions) +
                ", page:" + JSON.toJSONString(page) +
                '}';
    }
}
